﻿using System;
using System.Collections.Generic;
using System.Data.SqlClient;
using System.Linq;
using System.Threading.Tasks;
using System.Web;
using System.Web.Mvc;
using System.Web.Mvc.Html;
using AutoMapper;
using NTQOnlineExam.Services.CommandService.Examination;
using NTQOnlineExam.Services.DBCommand;
using NTQOnlineExam.Services.Models;
using NTQOnlineExam.Services.ReportService.Answer;
using NTQOnlineExam.Services.ReportService.Examination;
using NTQOnlineExam.Services.ReportService.Portfolio;
using NTQOnlineExam.Services.ReportService.Question;
using NTQOnlineExam.Services.ReportService.Section;
using NTQOnlineExam.Services.ReportService.Term;
using NTQOnlineExam.Services.SearchCriteria;
using NTQOnlineExamFrontend.Helpers;
using NTQOnlineExamFrontend.Models;
using WebMatrix.WebData;

namespace NTQOnlineExamFrontend.Controllers
{
    [Authorize]
    public class MemberController : Controller
    {
        private readonly IQuestionReportService _questionReportService;
        private readonly IAnswerReportService _answerReportService;
        private readonly ISectionReportService _sectionReportService;
        private readonly IExaminationCommandService _examinationCommandService;
        private readonly IExaminationReportService _examinationReportService;
        private readonly ITermReportService _termReportService;
        private readonly IPortfolioReportService _portfolioReportService;

        private const string ExamTokenListKey = "Exam_Token_List";
        private const string ExamResulTokentListKey = "Exam_Result_Token_List";
        public MemberController(IQuestionReportService questionReportService, IAnswerReportService answerReportService, ISectionReportService sectionReportService,
                                IExaminationCommandService examinationCommandService, IExaminationReportService examinationReportService,
                                ITermReportService termReportService, IPortfolioReportService portfolioReportService)
        {
            _questionReportService = questionReportService;
            _answerReportService = answerReportService;
            _sectionReportService = sectionReportService;
            _examinationCommandService = examinationCommandService;
            _examinationReportService = examinationReportService;
            _termReportService = termReportService;
            _portfolioReportService = portfolioReportService;
        }

        public ActionResult Index()
        {
            return View();
        }

        public ActionResult Login()
        {
            return View();
        }

        public ActionResult Home()
        {
            //return View();
            return RedirectToAction("Examination");
        }

        public ActionResult Examination(int? selectedTerm)
        {
            int total;
            var criteria = new SearchCriteria() { Keyword = string.Empty };
            criteria.AddSortOrder("TermName", SortOrder.Ascending);
            var termList = _portfolioReportService.GetCurrentUserActivePortfolio(criteria, false, 0, int.MaxValue, out total);
            var terms = new Dictionary<int, string>();
            foreach (var term in termList.Where(term => !terms.ContainsKey(term.TermId)))
            {
                terms.Add(term.TermId, term.TermName);
            }
            var selected = selectedTerm ?? (termList != null && termList.Count > 0 ? termList[0].TermId : 0);
            var model = new ExaminationViewModel { Terms = terms, SelectedTerm = selected };
            return View(model);
        }

        [HttpPost]
        public JsonResult GenerateExamToken(int termId)
        {
            try
            {
                var token = GenerateNewToken(ExamTokenListKey, termId);
                return Json(new { Result = "OK", Data = token });
            }
            catch (Exception ex)
            {
                return Json(new { Result = "ERROR", Message = ex.Message });
            }
        }

        public ActionResult Exam(int termId, string token)
        {
            if (_portfolioReportService.CheckTermNotInPortfolio(termId)) return new EmptyResult();
            var tokenList = GetTokenList(ExamTokenListKey);
            if (!tokenList.ContainsKey(termId) || tokenList[termId] != token) return new EmptyResult();
            tokenList.Remove(termId);
            UpdateTokenList(ExamTokenListKey, tokenList);

            var examModel = new ExamViewModel() { TermId = termId };
            return View(examModel);
        }

        public ActionResult ExamDetails(int sectionId, int termId, int pageIndex, bool isNewExamination)
        {
            var totalRecord = 0;
            var question = _questionReportService.GetQuestions("", termId, 0, pageIndex, 1, null, out totalRecord);
            var examinationDetailsModel = Mapper.Map<QuestionDTO, ExaminationDetailsViewModel>(question[0]);
            examinationDetailsModel.TotalQuestion = totalRecord;
            var answers = _answerReportService.GetAnswers(question[0].QuestionId);
            examinationDetailsModel.Answers = answers;
            return View("ExaminationDetails", examinationDetailsModel);
        }

        [HttpPost]
        public JsonResult GetSectionOptions(int? termId)
        {
            try
            {
                var results = _sectionReportService.GetSections(termId ?? 0).Select(c => new { DisplayText = c.SectionName, Value = c.SectionId });
                return Json(new { Result = "OK", Options = results });
            }
            catch (Exception ex)
            {
                return Json(new { Result = "ERROR", Message = ex.Message });
            }
        }

        [HttpPost]
        public JsonResult GetExamInformation(int termId)
        {
            try
            {
                var totalRecord = 0;
                //var question = _questionReportService.GetQuestions("", termId, sectionId, 0, 0, null, out totalRecord);
                var results = _examinationReportService.GetExamInformation(termId);
                totalRecord = results.Sum(n => n.TotalQuestion);
                return Json(new { Result = "OK", TotalRecord = totalRecord, Records = results });
            }
            catch (Exception ex)
            {
                return Json(new { Result = "ERROR", Message = ex.Message });
            }
        }

        public ActionResult ExaminationHistory()
        {
            IList<BreadcrumItem> breadcrumItems = new List<BreadcrumItem>();
            breadcrumItems.Add(new BreadcrumItem("Examination Administration", "/Member/Examination", false));
            breadcrumItems.Add(new BreadcrumItem("Exam Results and History", string.Empty, true));

            ViewData["Breadcrumb"] = breadcrumItems;

            return View(new ExaminationHistorySearchViewModel());
        }

        public ActionResult SearchExamHistory(string keyword, int pageIndex)
        {
            var sortItems = Utility.GetSortItems(Request);
            var searchCriteria = new SearchCriteria() { Keyword = keyword };
            foreach (var item in sortItems)
            {
                searchCriteria.AddSortOrder(item.SortExpression, item.SortOrder);
            }
            var exams = _examinationReportService.SearchExamsForCurrentUser(searchCriteria, ExaminationHistoryViewModel.PageSize, pageIndex);
            var model = new ExaminationHistoryViewModel() { Exams = exams.Items, SelectedPage = pageIndex, TotalRecords = exams.Count };
            return PartialView("_ExamHistory", model);
        }

        public ActionResult ExaminationResultDetail(int examId, string token)
        {
            var tokenList = GetTokenList(ExamResulTokentListKey);
            if (!tokenList.ContainsKey(examId) || tokenList[examId] != token) return new EmptyResult();
            tokenList.Remove(examId);
            UpdateTokenList(ExamResulTokentListKey, tokenList);

            var examDetail = _examinationReportService.GetById(examId);
            int totalRecord;
            var listQuestionAnswers = _questionReportService.GetQuestions(string.Empty, examDetail.TermId, 0, 0, 10000, string.Empty, out totalRecord);
            IList<int> questions = listQuestionAnswers.Select(x => x.QuestionId).ToList();
            var answers = _answerReportService.GetAnswerForQuestions(questions);
            return View("ExamResultDetail", new ExaminationDetailResultViewModel() { ExamDetail = examDetail, Answers = answers, QuestionAnswers = listQuestionAnswers });
        }

        public ActionResult SubmitExamination(Dictionary<string, string> examination, int sectionId, int termId)
        {
            try
            {
                var examinationId = 0;
                var examResultModel = ScoreCalculating(sectionId, termId, examination);
                if (examination.ContainsKey("0")) examination.Remove("0");
                var result = _examinationCommandService.CreateExamination(new AddExaminationCommand()
                {
                    Score = examResultModel.TotalScore,
                    TermId = termId,
                    UserId = WebSecurity.GetUserId(User.Identity.Name),
                    QuestionAnswers = examination
                }, out examinationId);
                examResultModel.ExamId = examinationId;
                var tokenToAccessResultPage = GenerateNewToken(ExamResulTokentListKey, examinationId);
                examResultModel.TokenToAccessResultPage = tokenToAccessResultPage;

                return View("FinalScore", examResultModel);
            }
            catch (Exception exception)
            {
                return Json(new { Result = "Fail", Error = exception.Message });
            }
        }

        #region Helpers
        private ExaminationResultViewModel ScoreCalculating(int sectionId, int termId, Dictionary<string, string> examination)
        {
            var examResultModel = new ExaminationResultViewModel();
            var totalRecord = 0;
            var listAnswer = _questionReportService.GetQuestionsForExamination(sectionId, termId, out totalRecord);
            var totalTrueQuestion = 0;
            var finalScore = 0;
            foreach (var questionExam in examination)
            {
                var answer = listAnswer.FirstOrDefault(n => n.QuestionId == Convert.ToInt32(questionExam.Key));
                if (answer != null && answer.AnswerId == Convert.ToInt32(questionExam.Value))
                {
                    totalTrueQuestion++;
                }
            }
            finalScore = Convert.ToInt32(Math.Round(Convert.ToDecimal(totalTrueQuestion) / Convert.ToDecimal(totalRecord) * 100));

            examResultModel.TotalQuestion = totalRecord;
            examResultModel.TotalTrueQuestion = totalTrueQuestion;
            examResultModel.TotalScore = finalScore;
            return examResultModel;
        }

        private string GenerateNewToken(string tokenKey, int objectKey)
        {
            var tokenList = GetTokenList(tokenKey);
            var token = Guid.NewGuid().ToString();
            if (tokenList.ContainsKey(objectKey)) tokenList[objectKey] = token;
            else tokenList.Add(objectKey, token);
            UpdateTokenList(tokenKey, tokenList);
            return token;

        }
        private IDictionary<int, string> GetTokenList(string key)
        {
            if (Session[key] != null)
            {
                return (Dictionary<int, string>)Session[key];
            }
            return new Dictionary<int, string>();
        }

        private void UpdateTokenList(string key, IDictionary<int, string> tokens)
        {
            Session[key] = tokens;
        }

        #endregion
    }
}
